package net.tensor.tensor.activiti.controller;

import net.tensor.tensor.activiti.bean.Content;
import net.tensor.tensor.activiti.util.SecurityUtil;
import org.activiti.api.model.shared.model.VariableInstance;
import org.activiti.api.process.model.ProcessDefinition;
import org.activiti.api.process.model.ProcessInstance;
import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * 这是一个测试controller
 * @author Q
 */
@RestController
public class DemoController {
    private final Logger logger = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    private ProcessRuntime processRuntime;

    @Autowired
    private TaskRuntime taskRuntime;

    @Autowired
    private SecurityUtil securityUtil;

    /**
     * 一个简单的测试接口
     */
    @GetMapping("/process")
    public void process() {

        // 模拟用户reviewer登录
        securityUtil.logInAs("reviewer");

        // 可使用流程
        listAvailableProcesses();

        // 开始一个流程
        ProcessInstance processInstance = startProcess();

        // 流程里的参数
        listProcessVariables(processInstance);

        // 完成正在流转的任务
        completeAvailableTasks();
    }

    /**
     * 该接口用来测试分组任务,用户信息都已在config类里配置好了
     * 另外也可以通过该接口的实现认识activiti7的task api如何使用
     */
    @GetMapping("/taskRelevant")
    public void taskRelevant() {
        // 模拟GROUP_activitiTeam组下的用户reviewer登录
        securityUtil.logInAs("reviewer");

        logger.info("reviewer创建了一个任务");
        taskRuntime.create(TaskPayloadBuilder.create()
                .withName("activitiTeam组下的第一个任务")
                .withDescription("写点描述")
                .withCandidateGroup("activitiTeam")
                .withPriority(10)
                .build());

        // 模拟GROUP_otherTeam组下的用户other登录
        securityUtil.logInAs("other");

        logger.info("看看用户other能不能看到用户reviewer创建的任务");
        Page<Task> tasks = taskRuntime.tasks(Pageable.of(0, 10));

        logger.info("other能看到的任务数: " + tasks.getTotalItems());

        // 模拟GROUP_activitiTeam组下的用户system登录
        securityUtil.logInAs("system");

        logger.info("看看用户system能不能看到用户reviewer创建的任务");
        tasks = taskRuntime.tasks(Pageable.of(0, 10));

        logger.info("system能看到的任务数: " + tasks.getTotalItems());

        // 让system来领取这个任务，领取完后其他人就都不能看到这个任务了，并且该任务的assignee变为system
        String availableTaskId = tasks.getContent().get(0).getId();
        taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(availableTaskId).build());

        logger.info("用户system完成任务");
        taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(availableTaskId).build());
    }

    /**
     * 这个接口是用来测试传参接收参数使用bean的情况
     */
    @GetMapping("/variableWithBean")
    public void variableWithBean() {
        securityUtil.logInAs("reviewer");

        Content content = pickRandomString();

        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yy HH:mm:ss");

        logger.info("启动一个带bean的参数的流程: " + content + " ，time: " + formatter.format(new Date()));

        ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder
                .start()
                .withProcessDefinitionKey("RankMovieId")
                .withName("Processing Content: " + content)
                .withVariable("content", content)
                .build());
        logger.info("开始一个流程实例: " + processInstance);

        Page<Task> tasks = taskRuntime.tasks(Pageable.of(0, 10));
        if (tasks.getTotalItems() > 0) {
            for (Task t : tasks.getContent()) {

                logger.info("领取任务: " + t.getId());
                taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(t.getId()).build());

                List<VariableInstance> variables = taskRuntime.variables(TaskPayloadBuilder.variables().withTaskId(t.getId()).build());
                VariableInstance variableInstance = variables.get(0);
                if (variableInstance.getName().equals("content")) {
                    Content contentToProcess = variableInstance.getValue();
                    logger.info("获取到的内容信息: " + contentToProcess);

                    if (contentToProcess.getBody().contains("activiti")) {
                        logger.info("同意内容");
                        contentToProcess.setApproved(true);
                    } else {
                        logger.info("不同意内容");
                        contentToProcess.setApproved(false);
                    }
                    taskRuntime.complete(TaskPayloadBuilder.complete()
                            .withTaskId(t.getId()).withVariable("content", contentToProcess).build());
                }


            }

        } else {
            logger.info("没有任务");
        }

    }

    private void completeAvailableTasks() {
        Page<Task> tasks = taskRuntime.tasks(Pageable.of(0,
                20));
        tasks.getContent().forEach(task -> {
            logger.info("正在流转的任务,{} ", task);
            listTaskVariables(task);
            taskRuntime.complete(TaskPayloadBuilder
                    .complete()
                    .withTaskId(task.getId())
                    .withVariable("rating", 5)
                    .build());
        });
    }

    private void listTaskVariables(Task task) {
        logger.info("可使用任务:");
        taskRuntime.variables(TaskPayloadBuilder
                .variables()
                .withTaskId(task.getId())
                .build())
                .forEach(variableInstance -> logger.info("\t> " + variableInstance.getName() + " -> " + variableInstance.getValue()));
    }

    private void listProcessVariables(ProcessInstance processInstance) {
        logger.info("流程参数:");
        List<VariableInstance> variables = processRuntime.variables(
                ProcessPayloadBuilder
                        .variables()
                        .withProcessInstance(processInstance)
                        .build());
        variables.forEach(variableInstance -> logger.info("\t> " + variableInstance.getName() + " -> " + variableInstance.getValue()));
    }

    private ProcessInstance startProcess() {
        ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder
                .start()
                .withProcessDefinitionKey("RankMovieId")
                .withName("myProcess")
                .withVariable("movieToRank",
                        "Lord of the rings")
                .build());
        logger.info("开始一个流程实例: " + processInstance);
        return processInstance;
    }

    private void listAvailableProcesses() {
        Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0,
                10));
        logger.info("可使用流程定义数:{}", processDefinitionPage.getTotalItems());
        for (ProcessDefinition pd : processDefinitionPage.getContent()) {
            logger.info("\t 流程: " + pd);
        }
    }

    private Content pickRandomString() {
        String[] texts = {"和平", "富强", "民主", "文明" +
                "法治",
                "乐观", "友善"};
        return new Content(texts[new Random().nextInt(texts.length)], false, null);
    }

}
